{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BIKE SHARING数据的回归分析和交叉检验超参调优"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#%%\n",
    "#本作业并未完全用Jupyter Notebook编写，\n",
    "#鉴于双显卡笔记本安装ubuntu虚拟机带来的显卡驱动问题，\n",
    "#会导致ubuntu只能于低分辨率下运行。\n",
    "#而windows环境下JupyterNotebook运行速度不佳（大目录），\n",
    "#Conda运行速度亦同，\n",
    "#因此选用了VSCODE+PIP INSTALL的方式搭建运行环境\n",
    "#------------------------------------------------------------------------------------------\n",
    "#Python版本为3.6.7，PIP版本为最新的18。JupyterNotebook也安装，并通过VSCODE插件调用来查看示范文件\n",
    "#------------------------------------------------------------------------------------------\n",
    "#Importing Libraries\n",
    "#%%\n",
    "import numpy as npy\n",
    "import pandas as pds\n",
    "import sklearn as skl\n",
    "import matplotlib as mpl\n",
    "import seaborn as sbn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 数据读取及变量筛除"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 731 entries, 0 to 730\n",
      "Data columns (total 16 columns):\n",
      "instant       731 non-null int64\n",
      "dteday        731 non-null object\n",
      "season        731 non-null int64\n",
      "yr            731 non-null int64\n",
      "mnth          731 non-null int64\n",
      "holiday       731 non-null int64\n",
      "weekday       731 non-null int64\n",
      "workingday    731 non-null int64\n",
      "weathersit    731 non-null int64\n",
      "temp          731 non-null float64\n",
      "atemp         731 non-null float64\n",
      "hum           731 non-null float64\n",
      "windspeed     731 non-null float64\n",
      "casual        731 non-null int64\n",
      "registered    731 non-null int64\n",
      "cnt           731 non-null int64\n",
      "dtypes: float64(4), int64(11), object(1)\n",
      "memory usage: 91.5+ KB\n"
     ]
    }
   ],
   "source": [
    "df_bike=pds.read_csv(\"day.csv\")\n",
    "df_bike.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Variable Selection: Drop instant, dteday, mnth, season, weekday和atemp. 原因是这些变量内部的决定性因素都可以被其他变量所解释。\n",
    "df_bike_y=df_bike[[\"cnt\",\"casual\",\"registered\"]]\n",
    "#instant与y无关。dteday级别过多。atemp是temp, hum和windspeed的函数，定义上多重共线性程度达到100%，因此舍弃这几个变量\n",
    "df_bike_x=df_bike.drop([ \"dteday\",\"atemp\",\"cnt\",\"casual\",\"registered\"],axis=1)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 将类别变量转换为0-1编码，同时标准化连续变量，生成测试集与训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 731 entries, 0 to 730\n",
      "Data columns (total 30 columns):\n",
      "yr_0            731 non-null uint8\n",
      "yr_1            731 non-null uint8\n",
      "mnth_1          731 non-null uint8\n",
      "mnth_2          731 non-null uint8\n",
      "mnth_3          731 non-null uint8\n",
      "mnth_4          731 non-null uint8\n",
      "mnth_5          731 non-null uint8\n",
      "mnth_6          731 non-null uint8\n",
      "mnth_7          731 non-null uint8\n",
      "mnth_8          731 non-null uint8\n",
      "mnth_9          731 non-null uint8\n",
      "mnth_10         731 non-null uint8\n",
      "mnth_11         731 non-null uint8\n",
      "mnth_12         731 non-null uint8\n",
      "season_1        731 non-null uint8\n",
      "season_2        731 non-null uint8\n",
      "season_3        731 non-null uint8\n",
      "season_4        731 non-null uint8\n",
      "weekday_0       731 non-null uint8\n",
      "weekday_1       731 non-null uint8\n",
      "weekday_2       731 non-null uint8\n",
      "weekday_3       731 non-null uint8\n",
      "weekday_4       731 non-null uint8\n",
      "weekday_5       731 non-null uint8\n",
      "weekday_6       731 non-null uint8\n",
      "holiday_0       731 non-null uint8\n",
      "holiday_1       731 non-null uint8\n",
      "weathersit_1    731 non-null uint8\n",
      "weathersit_2    731 non-null uint8\n",
      "weathersit_3    731 non-null uint8\n",
      "dtypes: uint8(30)\n",
      "memory usage: 21.5 KB\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0      1.250171\n",
       "1      0.479113\n",
       "2     -1.339274\n",
       "3     -0.263182\n",
       "4     -1.341494\n",
       "5     -0.770265\n",
       "6     -0.907726\n",
       "7     -0.646807\n",
       "8     -1.361096\n",
       "9     -1.018586\n",
       "10     0.410801\n",
       "11    -0.199176\n",
       "12    -1.106409\n",
       "13    -0.632804\n",
       "14    -0.907346\n",
       "15    -1.012734\n",
       "16    -0.635095\n",
       "17     1.642452\n",
       "18     0.799857\n",
       "19    -0.629242\n",
       "20    -1.200092\n",
       "21    -1.601148\n",
       "22    -1.344550\n",
       "23    -0.956604\n",
       "24    -0.076842\n",
       "25     1.648305\n",
       "26     0.418782\n",
       "27     1.160311\n",
       "28     0.167531\n",
       "29     0.662396\n",
       "         ...   \n",
       "701    1.373124\n",
       "702    0.980850\n",
       "703    0.743727\n",
       "704   -1.003951\n",
       "705   -0.837088\n",
       "706    0.957432\n",
       "707    1.990815\n",
       "708    1.949833\n",
       "709    2.087420\n",
       "710   -0.219396\n",
       "711   -0.629242\n",
       "712   -0.998099\n",
       "713    0.105549\n",
       "714    0.158243\n",
       "715    1.481441\n",
       "716    1.961538\n",
       "717    0.269483\n",
       "718   -0.017403\n",
       "719    0.281195\n",
       "720   -0.500430\n",
       "721   -1.311332\n",
       "722   -0.790246\n",
       "723    1.148093\n",
       "724    0.750985\n",
       "725    1.373124\n",
       "726    0.175807\n",
       "727   -0.266238\n",
       "728    0.878392\n",
       "729   -1.015664\n",
       "730   -0.354061\n",
       "Name: hum, Length: 731, dtype: float64"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#类别变量的0-1编码\n",
    "cat_var=['yr','mnth','season',\"weekday\",'holiday','weathersit']\n",
    "for col in cat_var:\n",
    "    df_bike_x[col]=df_bike_x[col].astype('object')\n",
    "df_bike_xdummies = df_bike_x[cat_var]\n",
    "df_bike_xdummies = pds.get_dummies(df_bike_xdummies)\n",
    "df_bike_xdummies.info()\n",
    "df_bike_xdummies.head()\n",
    "\n",
    "#连续变量的标准化，通过scipy.stats.zscore实现(未采纳归一化的策略)\n",
    "from scipy import stats\n",
    "cont_var = ['temp','hum','windspeed']\n",
    "for col in cont_var:\n",
    "    temp=stats.zscore(df_bike_x[cont_var])\n",
    "df_bike_xcontcs = pds.DataFrame(data=temp, columns=cont_var, index=df_bike_x.index)\n",
    "\n",
    "#拼接起最终的数据集，包含y和不包含y\n",
    "df_bike_formatted_x= pds.concat((df_bike['instant'],df_bike_xdummies,df_bike_xcontcs),axis = 1)\n",
    "df_bike_formatted= pds.concat((df_bike_formatted_x,df_bike['cnt']),axis = 1)\n",
    "df_bike_formatted_x.head()\n",
    "df_bike_formatted_x['hum']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(584, 34)\n",
      "(147, 34)\n",
      "(584,)\n",
      "(147,)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\program files\\python367\\lib\\site-packages\\pandas\\core\\frame.py:3697: SettingWithCopyWarning: \n",
      "A value is trying to be set on a copy of a slice from a DataFrame\n",
      "\n",
      "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n",
      "  errors=errors)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "X_train, X_test,cnt_train,cnt_test = train_test_split(df_bike_formatted_x, df_bike_formatted['cnt'],random_state=271828, test_size=0.2)\n",
    "print(X_train.shape)\n",
    "print(X_test.shape)\n",
    "print(cnt_train.shape)\n",
    "print(cnt_test.shape)\n",
    "testID = X_test['instant']\n",
    "X_train.drop(['instant'], axis=1, inplace = True)\n",
    "X_test.drop(['instant'], axis=1, inplace = True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 模型拟合与模型性能评价"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入必要的工具包\n",
    "from sklearn.linear_model import LinearRegression,Ridge,RidgeCV,Lasso,LassoCV,ElasticNet,ElasticNetCV\n",
    "#导入性能评价指标\n",
    "from sklearn.metrics import mean_squared_error,r2_score\n",
    "from sklearn.metrics import r2_score\n",
    "#导入可视化工具\n",
    "import matplotlib.pyplot as mpl_ppl\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE on Training set : 768.6389345094585\n",
      "RMSE on Test set : 722.2401987994747\n",
      "r2_score on Training set : 0.8422420201772856\n",
      "r2_score on Test set : 0.8593399697555577\n"
     ]
    }
   ],
   "source": [
    "#OLS线性回归\n",
    "lr = LinearRegression()\n",
    "lr.fit(X_train, cnt_train)\n",
    "cnt_train_pred_lr = lr.predict(X_train)\n",
    "cnt_test_pred_lr = lr.predict(X_test)\n",
    "\n",
    "rmse_train = npy.sqrt(mean_squared_error(cnt_train,cnt_train_pred_lr))\n",
    "rmse_test = npy.sqrt(mean_squared_error(cnt_test,cnt_test_pred_lr))\n",
    "print(\"RMSE on Training set :\", rmse_train)\n",
    "print(\"RMSE on Test set :\", rmse_test)\n",
    "\n",
    "r2_score_train_lr = r2_score( cnt_train,cnt_train_pred_lr)\n",
    "r2_score_test_lr = r2_score(cnt_test,cnt_test_pred_lr)\n",
    "print(\"r2_score on Training set :\", r2_score_train_lr)\n",
    "print(\"r2_score on Test set :\", r2_score_test_lr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best Lambda : 4.6415888336127775\n",
      "cv of rmse : [812.91891892 812.88824325 812.80459682 812.58451178 812.05942841\n",
      " 811.11101329 810.72326682 816.01549942 840.218075   914.4031283 ]\n",
      "RMSE on Training set : 770.9684626783423\n",
      "RMSE on Test set : 732.156604689386\n",
      "r2_score on Training set : 0.8412843311028488\n",
      "r2_score on Test set : 0.8554509101572663\n"
     ]
    }
   ],
   "source": [
    "#Ridge Regression岭回归\n",
    "\n",
    "# RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, normalize=False, scoring=None, cv=None, gcv_mode=None, store_cv_values=False)\n",
    "n_alphas=10\n",
    "alphas = npy.logspace(-2,2,n_alphas,10)\n",
    "ridge = RidgeCV(alphas = alphas,store_cv_values=True )\n",
    "\n",
    "# 2. 用训练数据度模型进行训练\n",
    "# RidgeCV采用的是广义交叉验证（Generalized Cross-Validation），留一交叉验证（N-折交叉验证）的一种有效实现方式\n",
    "ridge.fit(X_train,cnt_train)\n",
    "alpha = ridge.alpha_\n",
    "print(\"Best Lambda :\", alpha)\n",
    "# 交叉验证估计的测试误差\n",
    "mse_cv = npy.mean(ridge.cv_values_, axis = 0)\n",
    "rmse_cv = npy.sqrt(mse_cv)\n",
    "print(\"cv of rmse :\",rmse_cv)\n",
    "\n",
    "cnt_train_pred_ridge = ridge.predict(X_train)\n",
    "cnt_test_pred_ridge= ridge.predict(X_test)\n",
    "\n",
    "rmse_train = npy.sqrt(mean_squared_error(cnt_train,cnt_train_pred_ridge))\n",
    "rmse_test = npy.sqrt(mean_squared_error(cnt_test,cnt_test_pred_ridge))\n",
    "\n",
    "print(\"RMSE on Training set :\", rmse_train)\n",
    "print(\"RMSE on Test set :\" ,rmse_test)\n",
    "\n",
    "r2_score_train = r2_score(cnt_train,cnt_train_pred_ridge)\n",
    "r2_score_test = r2_score(cnt_test,cnt_test_pred_ridge)\n",
    "print(\"r2_score on Training set :\" ,r2_score_train)\n",
    "print(\"r2_score on Test set :\" ,r2_score_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSE on Training set : 768.6389345094585\n",
      "RMSE on Test set : 727.2686919525662\n",
      "Best Lambda : 2.811768697974228\n",
      "The r2 score of LassoCV on train is 0.8416096975381624\n",
      "The r2 score of LassoCV on test is 0.8573745010233795\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\program files\\python367\\lib\\site-packages\\sklearn\\model_selection\\_split.py:2053: FutureWarning: You should specify a value for 'cv' instead of relying on the default value. The default value will change from 3 to 5 in version 0.22.\n",
      "  warnings.warn(CV_WARNING, FutureWarning)\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'coefs' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-16-5bfe3abb7383>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     29\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'The r2 score of LassoCV on train is'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mr2_score\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcnt_train\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mcnt_train_pred_lasso\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     30\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'The r2 score of LassoCV on test is'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mr2_score\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcnt_test\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mcnt_test_pred_lasso\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 31\u001b[1;33m \u001b[0mcoefs\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m: name 'coefs' is not defined"
     ]
    }
   ],
   "source": [
    "#Lasso Regression lasso回归\n",
    "#RidgeCV缺省的score是mean squared errors \n",
    "# Lasso 范例代码及参数\n",
    "# class sklearn.linear_model.LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True, \n",
    "#                                    normalize=False, precompute=’auto’, max_iter=1000, \n",
    "#                                    tol=0.0001, copy_X=True, cv=None, verbose=False, n_jobs=1,\n",
    "#                                    positive=False, random_state=None, selection=’cyclic’)\n",
    "#Lasso可以自动确定最大的alpha，所以另一种设置alpha的方式是设置最小的alpha值（eps） 和 超参数的数目（n_alphas），\n",
    "#然后LassoCV对最小值和最大值之间在log域上均匀取值n_alphas个\n",
    "# np.logspace(np.log10(alpha_max * eps), np.log10(alpha_max),num=n_alphas)[::-1]\n",
    "\n",
    "n_alphas = 50\n",
    "alpha_range = npy.logspace(-2,2,n_alphas,10)\n",
    "lasso = LassoCV(alphas = alpha_range)\n",
    "lasso.fit(X_train, cnt_train)  \n",
    "cnt_test_pred_lasso = lasso.predict(X_test)\n",
    "cnt_train_pred_lasso = lasso.predict(X_train)\n",
    "\n",
    "rmse_test = npy.sqrt(mean_squared_error(cnt_test,cnt_test_pred_lasso))\n",
    "\n",
    "print(\"RMSE on Training set :\", rmse_train)\n",
    "print(\"RMSE on Test set :\" ,rmse_test)\n",
    "\n",
    "r2_score_train = r2_score(cnt_train,cnt_train_pred_lasso)\n",
    "r2_score_test = r2_score(cnt_test,cnt_test_pred_lasso)\n",
    "# 评估，使用r2_score评价模型在测试集和训练集上的性能\n",
    "alpha = lasso.alpha_\n",
    "print(\"Best Lambda :\", alpha)\n",
    "print('The r2 score of LassoCV on train is', r2_score(cnt_train,cnt_train_pred_lasso))\n",
    "print('The r2 score of LassoCV on test is', r2_score(cnt_test,cnt_test_pred_lasso))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "#三种模型得出结果过于接近。最终选择了OLS。\n",
    "df = pds.DataFrame({\"instant\":testID, 'cnt':cnt_test_pred_lr})\n",
    "df.to_csv('submission.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
